package com.csj.mvvm.ui.base

import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.csj.mvvm.api.HttpUtil
import com.csj.mvvm.api.error.ErrorResult
import com.csj.mvvm.api.error.ErrorUtil
import com.csj.mvvm.bean.HttpResponse
import com.csj.mvvm.utils.LogUtil
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import okhttp3.MediaType
import okhttp3.MultipartBody
import okhttp3.RequestBody
import okhttp3.ResponseBody
import java.io.File


open class BaseViewModel : ViewModel() {

    open var httpUtil = HttpUtil.getInstance()

    var isShowLoading = MutableLiveData<Boolean>()//是否显示loading
    var errorData = MutableLiveData<ErrorResult>()//错误信息
    var successData = MutableLiveData<Int>()//成功信息

    var apiIndex = 0 //表示api类型（确定是哪个api）

    fun showLoading() {
        isShowLoading.value = true
    }

    fun dismissLoading() {
        isShowLoading.value = false
    }

    fun showError(error: ErrorResult) {
        errorData.value = error
    }


    /**
     * 网络请求接口，可定制是否显示loading和错误提示
     * PS:如果接口Response的参数不一样，继承BaseViewModel的VM再参考launch方法重新写个网络请求方法（替换HttpResponse）
     */
    inline fun <reified M : HttpResponse> launch(
        noinline block: suspend CoroutineScope.() -> ResponseBody,//请求接口方法，M表示data实体泛型，调用时可将data对应的bean传入即可
        liveData: MutableLiveData<M>,
        isShowLoading: Boolean = true,
        isShowError: Boolean = true,
        index: Int = apiIndex
    ) {
        if (isShowLoading) showLoading()
        viewModelScope.launch {
            try {
                val result = withContext(Dispatchers.IO) {
                    httpUtil.getConverter().converter(block(), M::class.java)
                }
                if (result.errorCode == 0) {//请求成功
                    if (M::class.java.simpleName.equals("HttpResponse")) {
                        successData.value = index
                    } else {
                        result.apiIndex = index
                        liveData.value = result
                    }
                } else {
                    LogUtil.e("请求错误>>" + result.errorMsg)
                    showError(ErrorResult(result.errorCode, result.errorMsg, isShowError, index))
                }
            } catch (e: Throwable) {//接口请求失败
                LogUtil.e("请求异常>>" + e.message)
                val errorResult = ErrorUtil.getError(e)
                errorResult.index = index
                errorResult.show = isShowError
                showError(errorResult)
            } finally {//请求结束
                dismissLoading()
            }
        }
    }

    /**
     * 多文件上传【带参数】
     *
     * @param path     请求地址
     * @param files    list 文件集合
     * @param fileKey  与后台约定的 key
     * @param fileType 文件类型，如：image/png,image/jepg,vedio/mp4,text/plain 等
     * @param params   map 集合参数
     */
    fun uploadFiles(
        path: String,
        files: List<File>,
        fileKey: String?,
        fileType: String?,
        params: Map<String, String?>?
    ) {
        val builder = MultipartBody.Builder().setType(MultipartBody.FORM)
        if (params != null) {
            for ((key, value) in params) {
                builder.addFormDataPart(key, value)
            }
        }
        for (file in files) {
            builder.addFormDataPart(
                fileKey, file.name,
                RequestBody.create(
                    MediaType.parse(fileType ?: "multipart/form-data"),
                    file
                )
            )
        }
        val requestBody: RequestBody = builder.build()
        launch({
            httpUtil.getService().uploadFile(path, requestBody)
        }, MutableLiveData<HttpResponse>(), true)
    }

    fun uploadFile(
        path: String,
        file: File,
        fileKey: String,
        fileType: String,
        params: Map<String, String?>?
    ) {
        val files: MutableList<File> = ArrayList()
        files.add(file)
        uploadFiles(path, files, fileKey, fileType, params)
    }

    /**
     * get请求
     */
    inline fun <reified M : HttpResponse> get(
        path: String,
        params: Map<String, String?> = HashMap(),
        liveData: MutableLiveData<M> = MutableLiveData(),
        isShowLoading: Boolean = true,
        isShowError: Boolean = true
    ) {
        launch({
            httpUtil.getService().get(path, params)
        }, liveData, isShowLoading, isShowError)
    }

    /**
     * post请求
     */
    inline fun <reified M : HttpResponse> post(
        path: String,
        params: Map<String, String?> = HashMap(),
        liveData: MutableLiveData<M> = MutableLiveData(),
        isShowLoading: Boolean = true,
        isShowError: Boolean = true
    ) {
        launch({
            httpUtil.getService().post(path, params)
        }, liveData, isShowLoading, isShowError)
    }

    /**
     * post表单请求
     */
    inline fun <reified M : HttpResponse> postForm(
        path: String,
        params: Map<String, String?> = HashMap(),
        liveData: MutableLiveData<M> = MutableLiveData(),
        isShowLoading: Boolean = true,
        isShowError: Boolean = true
    ) {
        launch({
            httpUtil.getService().postForm(path, params)
        }, liveData, isShowLoading, isShowError)
    }

}
